Ruby 日記 29日目: Enumerableなメソッドを作るとき、ブロックが渡されなかった場合にはメソッドチェーンできるようにEnumeratorオブジェクトを返す
次のプログラムの実行結果を得るために__(1)__に適切なメソッドをすべて選んでください。
code:rb
module Enumerable
def with_prefix(prefix)
return to_enum(__(1)__, prefix) { size } unless block_given?
each do |char|
end
end
end
1,2,3,4,5.with_prefix("Awesome").reverse_each {|char| puts char
}
code:txt
# 実行結果
Awesome 5
Awesome 4
Awesome 3
Awesome 2
Awesome 1
選択肢:
:with_prefix
:reverse_each
__method__
:each
解説:
問題のコードの中で使われている to_enum は Object#to_enum のこと。
to_enum(method = :each, *args) -> Enumerator
to_enum(method = :each, *args) {|*args| ... } -> Enumerator
Enumerator.new(self, method, *args) を返します。
ブロックを指定した場合は Enumerator#size がブロックの評価結果を返 します。
code:rb
return to_enum(__(1)__, prefix) { size } unless block_given?
これは「ブロックが渡されなかった場合は __(1)__ メソッドに対して prefix 引数を渡し、ブロック引数として{ size }を渡す」ということ。
__(1)__はそのメソッド自身である必要があるね。
なので正解は「:with_prefix」と「__method__」のはず。確認してみよう。
code:gold/ex29/choice01.rb
module Enumerable
def with_prefix(prefix)
return to_enum(:with_prefix, prefix) { size } unless block_given?
each do |char|
end
end
end
1,2,3,4,5.with_prefix("Awesome").reverse_each {|char| puts char
}
code:sh
# ruby gold/ex29/choice01.rb
Awesome 5
Awesome 4
Awesome 3
Awesome 2
Awesome 1
/icons/hr.icon
code:gold/ex29/choice02.rb
module Enumerable
def with_prefix(prefix)
return to_enum(:reverse_each, prefix) { size } unless block_given?
each do |char|
end
end
end
1,2,3,4,5.with_prefix("Awesome").reverse_each {|char| puts char
}
code:sh
# ruby gold/ex29/choice02.rb
gold/ex29/choice02.rb:11:in `reverse_each': wrong number of arguments (1 for 0) (ArgumentError)
from gold/ex29/choice02.rb:11:in `each'
from gold/ex29/choice02.rb:11:in `reverse_each'
from gold/ex29/choice02.rb:11:in `<main>'
reverse_eachメソッドに引数は渡せないのにprefixを渡そうとしているからエラーになっているね。
/icons/hr.icon
code:gold/ex29/choice03.rb
module Enumerable
def with_prefix(prefix)
return to_enum(__method__, prefix) { size } unless block_given?
each do |char|
end
end
end
1,2,3,4,5.with_prefix("Awesome").reverse_each {|char| puts char
}
code:sh
# ruby gold/ex29/choice03.rb
Awesome 5
Awesome 4
Awesome 3
Awesome 2
Awesome 1
__method__ は定義されているそのメソッド自身を表すやつだね
現在のメソッド名を返します。 メソッドの外で呼ばれると nil を返します。
ふむふむ
現在のメソッド名が alias されたメソッドの場合でも alias 元のメソッド名 を返します。
へ〜
/icons/hr.icon
code:gold/ex29/choice04.rb
module Enumerable
def with_prefix(prefix)
return to_enum(:each, prefix) { size } unless block_given?
each do |char|
end
end
end
1,2,3,4,5.with_prefix("Awesome").reverse_each {|char| puts char
}
code:sh
# ruby gold/ex29/choice04.rb
gold/ex29/choice04.rb:11:in `each': wrong number of arguments (1 for 0) (ArgumentError)
from gold/ex29/choice04.rb:11:in `each'
from gold/ex29/choice04.rb:11:in `reverse_each'
from gold/ex29/choice04.rb:11:in `<main>'
eachメソッドに引数は渡せないのにprefixを渡そうとしているからエラーになっているね。
以上より、正解は「:with_prefix」と「__method__」だね。
/icons/hr.icon
with_prefix に直接(?)ブロックを渡す例で書いてみよう
code:gold/ex29/sample01.rb
module Enumerable
def with_prefix(prefix)
return to_enum(hoge, prefix) { size } unless block_given?
each do |char|
end
end
end
puts char
}
ブロックを渡した場合は3行目の to_enum が呼ばれない。
ので、メソッドはなんでもOKになっちゃってるね(実行されないのでエラーにならない)
ブロックを渡さない場合は hoge ってなんや?知らんぞ?というエラーになる。
code:sh
# ruby gold/ex29/sample01.rb
Awesome 1
Awesome 2
Awesome 3
Awesome 4
Awesome 5
gold/ex29/sample01.rb:3:in with_prefix': undefined local variable or method hoge' for 1, 2, 3, 4, 5:Array (NameError) from gold/ex29/sample01.rb:15:in `<main>'
/icons/hr.icon
むしろ、ブロックを渡すことを前提としたメソッドとして定義するのであれば(ブロックを渡さない場合の挙動を保証しないのであれば)、引数に&blockを指定しておいた方がいいね
code:gold/ex29/sample02.rb
module Enumerable
def with_prefix(prefix, &block)
each do |char|
end
end
end
puts char
}
code:sh
# ruby gold/ex29/sample02.rb
Awesome 1
Awesome 2
Awesome 3
Awesome 4
Awesome 5
gold/ex29/sample02.rb:4:in `block in with_prefix': no block given (yield) (LocalJumpError)
from gold/ex29/sample02.rb:3:in `each'
from gold/ex29/sample02.rb:3:in `with_prefix'
from gold/ex29/sample02.rb:13:in `<main>'
ブロックを渡さない場合は、ブロックが渡されるはずなのに渡されてないよ?ってエラーになるね。